#ifndef SCANNER_H_
#define SCANNER_H_

#include <string>
#include <iostream>
#include <fstream>
#include <vector>

#include "Observer.h"
#include "Token.h"
	
class Scanner : public ScannerInterface
{
public:
	Scanner(std::string filename);
	virtual ~Scanner();
	
	Token getToken();
	bool isEOF();

	std::string getFilename();
	
	void registerObserver(CharacterObserver* o);
	void registerObserver(TokenObserver* o);

	void removeObserver(CharacterObserver* o);
	void removeObserver(TokenObserver* o);
	 
private:
	enum { NO_TRANS, INIT, WHITESPACE, 
		UNDERSCORE, QUOTE, COMMENT, DOUBLE_QUOTE, NUMBER_SIGN, DOLLAR, AMPERSAND, DOT, 
		COLON,  QUESTION, AT, BACKSLASH, CARET, GRAVE_ACCENT, VERT_BAR, TILDE, 
		/* THESE STATES ARE ASSOCIATED WITH TOKENS, THEIR ORDER IS IMPORTANT */
		QT_AND_CHAR, /* state associated w the illegal char const length error */
		IDENTIFIER, NUM, CHAR_CONST,
		RIGHT_PARENTHESES, LEFT_PARENTHESES, SEMICOLON, PLUS, MINUS, ASTERISK, 
		SLASH, PERCENT, ASSIGNMENT, LT, EXCLAMATION, LOGIC_OR, 
		LOGIC_AND, GT, EQUAL, LTE, GTE, NOT_EQ, 
		RIGHT_BRACKET, LEFT_BRACKET, RIGHT_BRACE, LEFT_BRACE, COMMA,
		/* keywords */
		KW_MAIN, KW_INT, KW_CHAR, KW_VOID, KW_IF,
		KW_ELSE, KW_WHILE, KW_RETURN, KW_SCANF, KW_PRINTF,
		/* these are the partial keyword states */
		KW_C, KW_CH, KW_CHA, KW_E, KW_EL, KW_ELS, KW_I, KW_IN, KW_M, KW_MA, KW_MAI, KW_P,
		KW_PR, KW_PRI, KW_PRIN, KW_PRINT, KW_R, KW_RE, KW_RET, KW_RETU, KW_RETUR, KW_S, KW_SC, 
		KW_SCA, KW_SCAN, KW_V, KW_VO, KW_VOI, KW_W, KW_WH, KW_WHI, KW_WHIL,
		STATE_SENTRY /* sentry used for array sizing and looping */ };
	
	static const int FIRST_TOKEN_STATE=QT_AND_CHAR;
	static const int KEYWORDS=KW_MAIN;
	static const int PARTIAL_KEYWORDS=KW_C;
	
	std::string filename;
	std::ifstream sourceFile;
	bool scanningComment;
	bool endOfFile;	
	char currentChar;
	long currentLine;
	
	std::vector<CharacterObserver*> characterObservers;
	std::vector<TokenObserver*> tokenObservers;
	void notifyCharacterObservers(char c);
	void notifyTokenObservers(Token t);
	
	static int table[128][STATE_SENTRY];
	static int tokenVector[STATE_SENTRY];
	
	void initTable();
	void initTokenVector();
	
	char nextChar();
	void skipBlanks();	
};

#endif /*SCANNER_H_*/
